<template>
<div class="row">
  <my-add-ip-detail></my-add-ip-detail>
  <my-vid-preview></my-vid-preview>
  <div class="col-md-12">
    <my-navbar fixed="top">
      <template slot="left">            
        <button class="btn btn-default" @click.prevent="onScan">
          <span class="glyphicon glyphicon-plus"></span> {{$t("common.scan")}}
        </button>
        <button class="btn btn-default" @click.prevent="onClear">
          <span class="glyphicon glyphicon-refresh"></span> {{$t("common.clear")}}
        </button>
        <span class="control-label">{{$t("webapp.type")}}</span>
        <select class="form-control" v-model="moduleIndex" @change.prevent="onModuleChange">
          <option v-for="option in moduleOptions" :value="$index">{{option.text}}</option>
        </select>
        <span class="control-label">{{$t("webapp.duration")}}</span>
        <select class="form-control" v-model="duration" number>
          <option v-for="option in durationOptions" :value="option.value">{{option.text}}</option>
        </select>   
      </template>
      <template slot="right">
        <button class="btn btn-default" @click.prevent="onStartTest">
          {{$t("webapp.start")}}
        </button> 
        <button class="btn btn-default" @click.prevent="onEndTest">
          {{$t("webapp.end")}}
        </button>
      </template>
    </my-navbar>
  </div>
  <div class="col-md-12">
    <my-table :cfg="cfg" :list="showList" :loading="false"></my-table>
  </div>
</div>
</template>

<script>
import _ from 'lodash'
import async from 'async'
import ebus from 'libs/ebus.js'
import locales from './locales.js'
import toast from 'libs/toast.js'
import msgbox from 'libs/msgbox.js'
import {codeMsg} from 'libs/api.js'
import {http} from 'share/common/api.js'
import {readableTime} from 'libs/utils.js'
import debugCfg from 'share/debugCfg.js'

const minCntOfEnc = debugCfg.debugOn ? 1 : 3

export default {
  locales,
  data () {
    return {
      scanDevCnt: 0,
      duration: 48*60*60,
      durationOptions: [{
        value: 24*60*60,
        text: '24小时'
      }, {
        value: 48*60*60,
        text: '48小时'
      }, {
        value: 72*60*60,
        text: '72小时'
      }, {
        value: 96*60*60,
        text: '96小时'
      }],
      moduleIndex: 0,
      moduleOptions: [{
        port: 8080,
        devType: 'encoder',
        text: '输入接口机',
        test: /^codec\.founder100/,
        onStartTest: this.onStartTestEnc
      }, {
        port: 8080,
        devType: 'decoder',
        text: '输出接口机',
        test: /^codec\.founder100/,
        onStartTest: this.onStartTestDec
      }],
      cfg: {
        checkable: true,
        showHead: true,
        columns: [{
          field: 'ipaddr',
          width: '10%',
          name: '设备IP'
        }, {
          field: 'devType',
          width: '10%',
          name: '接口机类型',
          show: function(item) {
            let text = {
              encoder: '输入接口机',
              decoder: '输出接口机'
            }
            return text[item.devType] ? text[item.devType] : ''
          }      
        }, {
          field: 'softwareVersion',
          width: '10%',
          name: '软件版本号'        
        }, {
          field: 'status',
          width: '10%',
          name: '老化状态',
          show: function(item) {
            let statusText = {
              idle: '空闲',
              testing: '老化中',
              finished: '等待完成',
              error: '异常中止',
              unknown: '未知'
            }
            return statusText[item.status] ? statusText[item.status] : ''
          }
        }, {
          field: 'setDuration',
          width: '15%',
          name: '当前待老化时长',
          show: function(item) {
            return readableTime(item.setDuration)
          }
        }, {
          field: 'currDuration',
          width: '15%',
          name: '当前已老化时长',
          show: function(item) {
            return readableTime(item.currDuration)
          }
        }, {
          field: 'totalDuration',
          width: '15%',
          name: '累计老化时长',
          show: function(item) {
            return readableTime(item.totalDuration)
          }      
        }],
        operation: {
          name: this.$t("common.operation"),
          width: 'auto',
          actions: [{
            icon: 'glyphicon glyphicon-search',
            doClick: this.onShowLocation
          }, {
            icon: 'glyphicon glyphicon-play',
            doClick: this.onShowPreview,
            isShow: function(item) {
              return item.devType === 'encoder'
            }
          }]
        }
      },
      list: []
    }
  },
  computed: {
    module () {
      return this.moduleOptions[this.moduleIndex]
    },
    showList () {
      let order = this.module.devType === 'decoder' ? 'asc' : 'desc'
      return _.orderBy(this.list, ['devType', 'ipaddr'], [order, 'asc'])
    }
  },
  methods: {
    getCntOfDevType (devType) {
      var cnt = 0
      _.forEach(this.list, (item) => {
        if (item.devType === devType) {
          cnt++
        }
      })
      return cnt
    },
    onShowLocation (item) {
      let host = `http://${item.ipaddr}:7080`
      http(host, '/api/agingtest/cmd', 'POST', {action: 'showLocation'}, {timeout: 1000})
        .then(function(res) {
          if (res && res.data && res.data.code === 0) {
          } else {
            toast.e(this, this.$t('common.fail'), this.$t('error.code'), {code: res.data.code})
          }
        }.bind(this), function(res) {
          toast.e(this, this.$t('common.fail'), this.$t('error.noResponse'))
        }.bind(this))
    },
    onShowPreview (item) {
      ebus.emit('show-vid-preview', `ws://${item.ipaddr}:7080`)
    },
    onScan () {
      ebus.emit('show-add-ip-detail')
    },
    onClear () {
      this.list.splice(0, this.list.length)
    },
    onModuleChange () {
      let testDevType = this.module.devType
      _.forEach(this.list, (item) => {
        item._checked = false
        if ((item.status === 'idle')
          || (item.status === 'error')) {
          item._disableCheck = false
        } else {
          item._disableCheck = true
        }
      })
    },
    stepRemoveAllWindow (arg, cb) {
      console.log('removeAllWindow')
      this.stepCommon(arg, '/dev/multimedia/cmd', 'POST', {
        action: 'removeAllWindow'
      }, cb)
    },
    stepOpenWindows (arg, cb) {
      var windows = []
      _.forEach(arg.windows, function(windowCfg) {
        windows.push({
          portName: 'vpOut_0',
          windowId: windowCfg.windowId,
          audPortName: '',
          playAudio: 0,
          url: windowCfg.url,
          windowInfo: {
            layer: windowCfg.layer,
            displaySrcCoordinate: {
              topHoriz: 0,
              topVerti: 0,
              bottomHoriz: 192,
              bottomVerti: 192                  
            },
            displayDstCoordinate: windowCfg.displayDstCoordinate,
          }
        })
      })
      this.stepCommon(arg, '/dev/multimedia/cmd', 'POST', {
        action: 'updateWindowList',
        paramlist: windows
      }, cb)
    },
    openWindows (decoder, encoders, callback) {
      let host = `http://${decoder.ipaddr}:7080`
      let arg = {
        host,
        windows: [{
          url: '',
          layer: 1,
          windowId: 1,
          displayDstCoordinate: {
            topHoriz: 0,
            topVerti: 3,
            bottomHoriz: 6,
            bottomVerti: 9
          }
        }, {
          url: '',
          layer: 2,
          windowId: 2,
          displayDstCoordinate: {
            topHoriz: 6,
            topVerti: 0,
            bottomHoriz: 12,
            bottomVerti: 6
          }
        }, {
          url: '',
          layer: 3,
          windowId: 3,
          displayDstCoordinate: {
            topHoriz: 6,
            topVerti: 6,
            bottomHoriz: 12,
            bottomVerti: 12
          }
        }]
      }
      _.forEach(arg.windows, (item, index) => {
        if (index < encoders.length) {
          item.url = `rtsp://${encoders[index].ipaddr}:554/main`
        } else {
          item.url = ''
        }
      })
      async.waterfall([
        function(cb) {
          cb(null, arg)
        }, 
        this.stepLogin,
        this.stepOpenWindows
        ], 
        function (err) {
          if (err) {
            console.log(err)
            toast.e(this, this.$t('common.fail'), err.msg)
          }
          callback(err)
        }.bind(this)
      )  
    },
    onStartTestOpenWindows (encoders, decoders, cb) {
      async.eachOf(decoders, function(decoder, index, callback) {
        var showEncoders = []
        showEncoders.push(encoders[(index * 3) % encoders.length])
        showEncoders.push(encoders[((index * 3) + 1) % encoders.length])
        showEncoders.push(encoders[((index * 3) + 2) % encoders.length])
        this.openWindows(decoder, showEncoders, callback)
      }.bind(this), function(err) {
        if (!err) {
          cb()
        }
      })
    },
    startTestCmd (devs) {
      _.forEach(devs, function(item) {
        let host = `http://${item.ipaddr}:7080`
        http(host, '/api/agingtest/cmd', 'POST', {
          action: 'startTest',
          paramlist: {
            duration: this.duration
          }
        }).then(function(res) {
          if (res && res.data && res.data.code === 0) {
            item.status = 'testing',
            item.setDuration = this.duration
            this.onModuleChange()
          } else {
            toast.code(this, res.data)
          }
        }.bind(this), function(res) {
          toast.e(this, this.$t('common.fail'), this.$t('error.noResponse'))
        }.bind(this))        
      }.bind(this))
    },
    onStartTestEnc (devs) {
      var encoders = _.filter(devs, {devType: 'encoder'})
      var decoders = _.filter(devs, {devType: 'decoder'})

      if (encoders.length <= 0) {
        toast.e(this, this.$t('common.fail'), this.$t('error.unselectedObj', {obj: this.$t('common.encoder')}))
        return
      }

      if (decoders.length <= 0) {
        toast.e(this, this.$t('common.fail'), this.$t('error.unselectedObj', {obj: this.$t('common.decoder')}))
        return
      }

      if (encoders.length > decoders.length * 3) {
        toast.e(this, this.$t('common.fail'), this.$t('error.tooFewItemsOfObj', {obj: this.$t('common.decoder')}))
        return
      }

      this.onStartTestOpenWindows(encoders, decoders, function() {
        this.startTestCmd(encoders)
      }.bind(this))
    },
    onStartTestDec (devs) {
      var encoders = _.filter(devs, {devType: 'encoder'})
      var decoders = _.filter(devs, {devType: 'decoder'})

      if (decoders.length <= 0) {
        toast.e(this, this.$t('common.fail'), this.$t('error.unselectedObj', {obj: this.$t('common.decoder')}))
        return
      }

      if (encoders.length < minCntOfEnc) {
        toast.e(this, this.$t('common.fail'), this.$t('error.tooFewItemsOfObj', {obj: this.$t('common.encoder')}))
        return
      }

      this.onStartTestOpenWindows(encoders, decoders, function() {
        this.startTestCmd(decoders)
      }.bind(this))
    },
    onStartTest () {
      var devs = _.filter(this.list, {_checked: true})

      this.module.onStartTest(devs)
    },
    stepCommon (arg, uri, method, req, cb) {
      http(arg.host, uri, method, req).then(function(res) {
        if (res && res.data && res.data.code === 0) {
          cb && cb(null, arg)
        } else {
          cb && cb(codeMsg(this, res.data))
        }
      }.bind(this), function(res) {
        cb && cb({msg: 'error'})
      })
    },
    stepLogin (arg, cb) {
      this.stepCommon(arg, '/api/auth/login', 'POST', {
        username: 'api',
        password: 'api'
      }, cb)
    },
    stepSendFinishCmd (arg, cb) {
      this.stepCommon(arg, '/api/agingtest/cmd', 'POST', {
        action: 'endTest'
      }, cb)
    },
    stepFactoryReset (arg, cb) {
      this.stepCommon(arg, '/api/common/cmd', 'POST', {
        action: 'runShell',
        paramlist: {
          shName: 'factoryReset.sh'
        }        
      }, cb)
    },
    stepShutdown (arg, cb) {
      this.stepCommon(arg, '/api/agingtest/cmd', 'POST', {
        action: 'shutdown'
      }, null)
      cb()
    },
    onEndTest () {
      let finished = _.filter(this.list, {status: 'finished'})
      if (finished.length <= 0) {
        toast.w(this, this.$t('common.finish'), this.$t('error.notFound'))
        return
      }

      msgbox.showWait(this.$t('alert.plzWait'), this.$t('common.processing'), -1)

      async.each(finished, function(item, callback) {
        let host = `http://${item.ipaddr}:7080`
        async.waterfall([
          function(cb) {
            cb(null, {host})      
          }, 
          this.stepLogin,
          this.stepSendFinishCmd,
          this.stepFactoryReset,
          this.stepShutdown
          ], 
          function (err) {
            if (err) {
              toast.e(this, this.$t('common.fail'), err.msg)
              cb({msg: 'error'})
            } else {
              callback()
            }
          }.bind(this)
        )        
      }.bind(this), function(err) {
        setTimeout(function() {
          msgbox.close()
        }, 3000)
        if (!err) {
          this.onClear()
          setTimeout(function() {
            toast.i(this, this.$t('common.finish'), this.$t('webapp.plzRemove'))
          }.bind(this), 3500)
        }
      }.bind(this))
    },
    getAgingTestState (ipaddr) {
      let host = `http://${ipaddr}:7080`
      http(host, '/api/agingtest/state', 'GET', null, {timeout: 1000})
        .then(function(res) {
          var devItem = _.find(this.list, {ipaddr})
          if (devItem) {
            if (res && res.data && res.data.code === 0) {
              let _info = res.data.data._info
              devItem.setDuration = _info.setDuration
              devItem.currDuration = _info.currDuration
              devItem.totalDuration = _info.totalDuration
              if (devItem.status != _info.status) {
                devItem.status = _info.status
                this.onModuleChange()
              }
            }
          }
        }.bind(this), function(res) {
        })
    },
    autoCheck () {
      let testing = _.filter(this.list, (item) => {
        return item.status === 'testing' || item.status === 'finished'
      })
      _.forEach(testing, function(item) {
        this.getAgingTestState(item.ipaddr)
      }.bind(this))
    },
    scanDev (ipaddr, callback) {
      let module = this.moduleOptions[this.moduleIndex]
      let host = `http://${ipaddr}:${module.port}`
      let test = module.test

      http(host, '/api/platform/cfg', 'GET', null, {timeout: 1000})
      .then(function(res) {
        if (res && res.data && res.data.code === 0) {
          let platformInfo = res.data.data
          if (test.test(platformInfo.devModel)) {
            this.list.push({
              ipaddr: ipaddr,
              devType: platformInfo.devType,
              softwareVersion: platformInfo.softwareVersion,
              setDuration: 0,
              currDuration: 0,
              totalDuration: 0,
              status: 'unknown',
              _checked: false,
              _disableCheck: true
            }) 
            this.getAgingTestState(ipaddr)
            this.scanDevCnt++         
          }
        }
        callback()
      }.bind(this), function(res) {
        callback()
      })
    },
    onAddIp (ipList) {
      if (ipList.length > 15) {
        msgbox.showWait(this.$t('alert.plzWait'), this.$t('common.processing'), -1)
      }
      this.scanDevCnt = 0
      async.eachLimit(ipList, 15, function(item, callback) {
        let dev = _.find(this.list, {ipaddr: item})
        if (dev) {
          callback()
          return
        }
        this.scanDev(item, callback)
      }.bind(this), function(err) {
        if (ipList.length > 15) {
          msgbox.close()
        }
        if (this.scanDevCnt > 0) {
          toast.s(this, this.$t('common.finish'), this.$t('alert.findResult', {cnt: this.scanDevCnt}))
          this.onModuleChange()
        } else {
          toast.w(this, this.$t('common.finish'), this.$t('error.notFound'))
        }
      }.bind(this))
    }
  },
  ready () {
    if (debugCfg.debugOn) {
      this.durationOptions.push({
        value: 2*60*60,
        text: '2小时'        
      })
    }
    ebus.on('add-ip', this.onAddIp)
    this.timer = setInterval(this.autoCheck, 30000)
  },
  beforeDestroy () {
    if (this.timer) {
      clearInterval(this.timer)
      this.timer = null
    }
  }
}
</script>

<style>
body { 
  padding-top: 70px; 
}
</style>